package wangwenjun.phase3.executor.unchecked;

import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import util.ThreadUtil;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

/**
 * @author ChangLiang
 * @date 2020/6/23
 */
@Slf4j
public class UncheckedExceptionTestV2 {

    @Test
    @DisplayName("test thread monitor pattern")
    public void test2() throws InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        IntStream.range(0, 10).boxed().forEach(i -> executorService.execute(
                new MyTask(i) {
                    @Override
                    protected void onStart() {
                        log.warn("onStart");
                    }

                    @Override
                    protected void onRunning() {
                        if (i % 2 == 0) {
                            int j = 1 / 0;
                        }
                    }

                    @Override
                    protected void onFinish() {
                        log.info("taskId:{} finished", i);
                    }

                    @Override
                    protected void onError(Throwable cause) {
                        log.error("taskId:{} error", i);
                        log.error(ThreadUtil.exceptionToString(cause));
                    }
                }
        ));
        executorService.shutdown();
        executorService.awaitTermination(10, TimeUnit.MINUTES);
        log.warn("test#finish");
    }

    private abstract static class MyTask implements Runnable {
        protected final int taskId;

        private MyTask(int taskId) {
            this.taskId = taskId;
        }

        @Override
        public void run() {
            try {
                this.onStart();
                this.onRunning();
                this.onFinish();
            } catch (Exception e) {
                this.onError(e);
            }
        }

        protected abstract void onStart();

        protected abstract void onRunning();

        protected abstract void onFinish();

        protected abstract void onError(Throwable cause);

    }
}
